home *** CD-ROM | disk | FTP | other *** search
/ ASME's Mechanical Engine…ing Toolkit 1997 December / ASME's Mechanical Engineering Toolkit 1997 December.iso / c_lang / sc.zoo / sc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-06-03  |  29.8 KB  |  1,430 lines

  1. /*    SC    A Spreadsheet Calculator
  2.  *        Main driver
  3.  *
  4.  *        original by James Gosling, September 1982
  5.  *        modifications by Mark Weiser and Bruce Israel,
  6.  *            University of Maryland
  7.  *
  8.  *              More mods Robert Bond, 12/86
  9.  *
  10.  */
  11.  
  12.  
  13. #include <signal.h>
  14. #include <curses.h>
  15.  
  16. #ifdef BSD42
  17. #include <strings.h>
  18. #else
  19. #ifndef SYSIII
  20. #include <string.h>
  21. #endif
  22. #endif
  23.  
  24. #include <stdio.h>
  25. #include "sc.h"
  26.  
  27. char *getenv();
  28.  
  29. #ifdef SYSV3
  30. void exit();
  31. #endif
  32.  
  33. /* default column width */
  34.  
  35. #define DEFWIDTH 10
  36. #define DEFPREC   2
  37.  
  38. #define MAXCMD 160    /* for ! command below */
  39.  
  40. /* Globals defined in sc.h */
  41.  
  42. struct ent *tbl[MAXROWS][MAXCOLS];
  43. int strow, stcol;
  44. int currow, curcol;
  45. int savedrow, savedcol;
  46. int FullUpdate;
  47. int maxrow, maxcol;
  48. int fwidth[MAXCOLS];
  49. int precision[MAXCOLS];
  50. char col_hidden[MAXCOLS];
  51. char row_hidden[MAXROWS];
  52. char line[1000];
  53. int changed;
  54. struct ent *to_fix;
  55. int modflg;
  56. int numeric;
  57. char *mdir;
  58. int showsc, showsr;    /* Starting cell for highlighted range */
  59.  
  60. char curfile[1024];
  61. char    revmsg[80];
  62.  
  63. int  linelim = -1;
  64. int  showme = 1;    /* 1 to display the current cell in the top line */
  65. int  showrange;        /* Causes ranges to be highlighted */
  66. int  lastmx, lastmy;    /* Screen address of the cursor */
  67. int  lastcol;        /* Spreadsheet Column the cursor was in last */
  68. char *under_cursor = " "; /* Data under the < cursor */
  69. char *rev = "$Revision: 5.1 $";
  70.  
  71. int seenerr;
  72.  
  73. yyerror (err)
  74. char *err; {
  75.     if (seenerr) return;
  76.     seenerr++;
  77.     (void) move (1,0);
  78.     (void) clrtoeol ();
  79.     (void) printw ("%s: %.*s<=%s",err,linelim,line,line+linelim);
  80. }
  81.  
  82. struct ent *
  83. lookat(row,col){
  84.     register struct ent **p;
  85.     if (row < 0)
  86.     row = 0;
  87.     else if (row > MAXROWS-1) 
  88.     row = MAXROWS-1;
  89.     if (col < 0) 
  90.     col = 0;
  91.     else if (col > MAXCOLS-1)
  92.     col = MAXCOLS-1;
  93.     p = &tbl[row][col];
  94.     if (*p==0) {
  95.     *p = (struct ent *) xmalloc ((unsigned)sizeof (struct ent));
  96.     if (row>maxrow) maxrow = row;
  97.     if (col>maxcol) maxcol = col;
  98.     (*p)->label = 0;
  99.     (*p)->flags = 0;
  100.     (*p)->row = row;
  101.     (*p)->col = col;
  102.     (*p)->expr = 0;
  103.     (*p)->v = (double) 0.0;
  104.     }
  105.     return *p;
  106. }
  107.  
  108. /*
  109.  * This structure is used to keep ent structs around before they
  110.  * are deleted to allow the sync_refs routine a chance to fix the
  111.  * variable references.
  112.  * We also use it as a last-deleted buffer for the 'p' command.
  113.  */
  114.  
  115. free_ent(p)
  116. register struct ent *p;
  117. {
  118.     p->next = to_fix;
  119.     to_fix = p;
  120.     p->flags |= is_deleted;
  121. }
  122.  
  123. flush_saved()
  124. {
  125.     register struct ent *p;
  126.     register struct ent *q;
  127.  
  128.     if (!(p = to_fix))
  129.     return;
  130.     while (p) {
  131.     (void) clearent(p);
  132.     q = p->next;
  133.     xfree((char *)p);
  134.     p = q;
  135.     }
  136.     to_fix = 0;
  137. }
  138.  
  139. update () {
  140.     register    row,
  141.                 col;
  142.     register struct ent **p;
  143.     int     mxcol;
  144.     int     mxrow;
  145.     int     rows;
  146.     int     cols;
  147.     int     minsr, minsc, maxsr, maxsc;
  148.     register r;
  149.     register i;
  150.  
  151.     while (row_hidden[currow])   /* You can't hide the last row or col */
  152.     currow++;
  153.     while (col_hidden[curcol])
  154.     curcol++;
  155.     /* First see if the last display still covers curcol */
  156.     if (stcol <= curcol) { 
  157.     for (i = stcol, cols = 0, col = RESCOL;
  158.             (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
  159.         cols++;
  160.         if (col_hidden[i])
  161.         continue;
  162.         col += fwidth[i];
  163.     }
  164.     }
  165.     while (stcol + cols - 1 < curcol || curcol < stcol) {
  166.     FullUpdate++;
  167.     if (stcol - 1 == curcol) {    /* How about back one? */
  168.         stcol--;
  169.     } else if (stcol + cols == curcol) {   /* Forward one? */
  170.         stcol++;
  171.     } else {
  172.         /* Try to put the cursor in the center of the screen */
  173.         col = (COLS - RESCOL - fwidth[curcol]) / 2 + RESCOL; 
  174.         stcol = curcol;
  175.         for (i=curcol-1; i >= 0 && col-fwidth[i] > RESCOL; i--) {
  176.         stcol--;
  177.         if (col_hidden[i])
  178.             continue;
  179.         col -= fwidth[i];
  180.         }
  181.     }
  182.     /* Now pick up the counts again */
  183.     for (i = stcol, cols = 0, col = RESCOL;
  184.             (col + fwidth[i]) < COLS-1 && i < MAXCOLS; i++) {
  185.         cols++;
  186.         if (col_hidden[i])
  187.         continue;
  188.         col += fwidth[i];
  189.     }
  190.     }
  191.     /* Now - same process on the rows */
  192.     if (strow <= currow) { 
  193.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
  194.         rows++;
  195.         if (row_hidden[i])
  196.         continue;
  197.         row++;
  198.     }
  199.     }
  200.     while (strow + rows - 1 < currow || currow < strow) {
  201.     FullUpdate++;
  202.     if (strow - 1 == currow) {    /* How about up one? */
  203.         strow--;
  204.     } else if (strow + rows == currow) {   /* Down one? */
  205.         strow++;
  206.     } else {
  207.         /* Try to put the cursor in the center of the screen */
  208.         row = (LINES - RESROW) / 2 + RESROW; 
  209.         strow = currow;
  210.         for (i=currow-1; i >= 0 && row-1 > RESROW; i--) {
  211.         strow--;
  212.         if (row_hidden[i])
  213.             continue;
  214.         row--;
  215.         }
  216.     }
  217.     /* Now pick up the counts again */
  218.     for (i = strow, rows = 0, row=RESROW; row<LINES && i<MAXROWS; i++) {
  219.         rows++;
  220.         if (row_hidden[i])
  221.         continue;
  222.         row++;
  223.     }
  224.     }
  225.     mxcol = stcol + cols - 1;
  226.     mxrow = strow + rows - 1;
  227.     if (FullUpdate) {
  228.     (void) move (2, 0);
  229.     (void) clrtobot ();
  230.     (void) standout();
  231.     for (row=RESROW, i=strow; i <= mxrow; i++) {
  232.         if (row_hidden[i]) 
  233.         continue;
  234.         (void) move(row,0);
  235. #if MAXROW < 1000
  236.         (void) printw("%-*d", RESCOL-1, i);
  237. #else
  238.         (void) printw("%-*d", RESCOL, i);
  239. #endif
  240.         row++;
  241.     }
  242.     (void) move (2,0);
  243.     (void) printw("%*s", RESCOL, " ");
  244.     for (col=RESCOL, i = stcol; i <= mxcol; i++) {
  245.         register int k;
  246.         if (col_hidden[i])
  247.         continue;
  248.         (void) move(2, col);
  249.         k = fwidth[i]/2;
  250.         if (k == 0)
  251.         (void) printw("%1s", coltoa(i));
  252.         else
  253.             (void) printw("%*s%-*s", k, " ", fwidth[i]-k, coltoa(i));
  254.         col += fwidth[i];
  255.     }
  256.     (void) standend();
  257.     }
  258.  
  259.     /* Get rid of the cursor standout */
  260.     (void) move(lastmx, lastmy);
  261.     if (showme)
  262.         repaint(lastmx, lastmy, fwidth[lastcol]);
  263.  
  264.     if (showrange && showme) {
  265.     minsr = showsr < currow ? showsr : currow;
  266.     minsc = showsc < curcol ? showsc : curcol;
  267.     maxsr = showsr > currow ? showsr : currow;
  268.     maxsc = showsc > curcol ? showsc : curcol;
  269.     (void) move(1,0);
  270.     (void) clrtoeol();
  271.         (void) printw("Default range - %s", r_name(minsr, minsc, maxsr, maxsc));
  272.     }
  273.  
  274.     /* Repaint the visible screen */
  275.     for (row = strow, r = RESROW; row <= mxrow; row++) {
  276.     register c = RESCOL;
  277.     int do_stand = 0;
  278.     int fieldlen;
  279.     int nextcol;
  280.  
  281.     if (row_hidden[row])
  282.         continue;
  283.     for (p = &tbl[row][col = stcol]; col <= mxcol;
  284.              p += nextcol - col,  col = nextcol, c += fieldlen) {
  285.  
  286.         nextcol = col+1;
  287.         if (col_hidden[col]) {
  288.         fieldlen = 0;
  289.         continue;
  290.         }
  291.  
  292.         fieldlen = fwidth[col];
  293.         if (showrange && showme && (row >= minsr) && (row <= maxsr) &&
  294.                    (col >= minsc) && (col <= maxsc)) {
  295.         do_stand = 1;
  296.         }
  297.         if (*p && ((*p) -> flags & is_changed || FullUpdate) || do_stand) {
  298.         char   *s;
  299.         (void) move (r, c);
  300.         if (!*p)
  301.             *p = lookat(row, col);
  302.         if (do_stand) {
  303.             (void) standout();
  304.             (*p) -> flags |= is_changed; 
  305.         } else {
  306.             (*p) -> flags &= ~is_changed;
  307.         }
  308.         if ((*p) -> flags & is_valid) {
  309.             char field[1024];
  310.             (void)sprintf(field,"%*.*f", fwidth[col],
  311.                              precision[col], (*p)->v);
  312.             if(strlen(field) > fwidth[col]) {
  313.             for(i = 0; i<fwidth[col]; i++)
  314.                 (void)addch('*');
  315.             } else {
  316.             (void)addstr(field);
  317.             }
  318.         }
  319.         if (s = (*p) -> label) {
  320.             char field[1024];
  321.             int  slen;
  322.             char *start, *last;
  323.             register char *fp;
  324.             struct ent *nc;
  325.  
  326.             /* This figures out if the label is allowed to
  327.                slop over into the next blank field */
  328.             slen = strlen(s);
  329.             while(slen>fieldlen && nextcol<=mxcol &&
  330.                !((nc = lookat(row,nextcol))->flags & is_valid) &&
  331.                !(nc->label)) {
  332.  
  333.             if (!col_hidden[nextcol])
  334.                 fieldlen += fwidth[nextcol];
  335.  
  336.                 nextcol++;
  337.             }
  338.             if (slen > fieldlen)
  339.             slen = fieldlen;
  340.  
  341.             /* Now justify and print */
  342.             start = (*p)->flags & is_leftflush ? field 
  343.                         : field + fieldlen - slen;
  344.             last = field+fieldlen;
  345.             fp = field;
  346.             while (fp < start)
  347.             *fp++ = ' ';
  348.             while (slen--)
  349.             *fp++ = *s++;
  350.             if (!((*p)->flags & is_valid) || fieldlen != fwidth[col]) 
  351.                 while (fp < last)
  352.                 *fp++ = ' ';
  353.             *fp = 0;
  354.             (void) mvaddstr(r, c, field);
  355.         }
  356.         if (!((*p)->flags & is_valid) && !(*p)->label) {
  357.             /* Need to repaint a blank cell */
  358.             (void) printw ("%*s", fwidth[col], " ");
  359.         }
  360.         if (do_stand) {
  361.             (void) standend();
  362.             do_stand = 0;
  363.         }
  364.         }
  365.     }
  366.     r++;
  367.     }
  368.         
  369.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  370.     if((inch() & 0x7f) == '<')
  371.         (void) addstr(under_cursor);
  372.     lastmy =  RESROW;
  373.     for (row = strow; row < currow; row++)
  374.     if (!row_hidden[row])
  375.         lastmy += 1;
  376.     lastmx = RESCOL;
  377.     for (col = stcol; col < curcol; col++)
  378.     if (!col_hidden[col])
  379.         lastmx += fwidth[col];
  380.     lastcol = curcol;
  381.     (void) move(lastmx, lastmy);
  382.     if (showme) {
  383.         (void) standout();
  384.         repaint(lastmx, lastmy, fwidth[lastcol]);
  385.         (void) standend();
  386.     }
  387.     (void) move(lastmy, lastmx+fwidth[lastcol]);
  388.     *under_cursor = (inch() & 0x7f);
  389.     (void) addstr("<");
  390.  
  391.     (void) move (0, 0);
  392.     (void) clrtoeol ();
  393.     if (linelim >= 0) {
  394.     (void) addstr (">> ");
  395.     (void) addstr (line);
  396.     } else {
  397.     if (showme) {
  398.         register struct ent *p1;
  399.  
  400.             (void) printw("%s%d", coltoa(curcol), currow);
  401.         p1 = tbl[currow][curcol];
  402.         if (p1 && ((p1->flags & is_valid) || p1->label)) {
  403.         if (p1->expr) {
  404.             linelim = 0;
  405.             editexp(currow, curcol);
  406.         } else if (p1->label) {
  407.             (void) sprintf(line, "%s", p1->label);
  408.         } else {
  409.             (void) sprintf(line, "%.15g", p1->v);
  410.         }
  411.         (void) addstr("[");
  412.         (void) addstr (line);
  413.         (void) addstr("]");
  414.         linelim = -1;
  415.         } else {
  416.         (void) addstr("[]");
  417.         }
  418.     }
  419.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  420.     }
  421.     if (revmsg[0]) {
  422.     (void) move(0, 0);
  423.     (void) printw(revmsg);
  424.     revmsg[0] = 0;
  425.     (void) move (lastmy, lastmx + fwidth[lastcol]);
  426.     }
  427.     FullUpdate = 0;
  428. }
  429.  
  430. repaint(x, y, len)
  431. {
  432.     char *buf;
  433.  
  434.     buf = " ";
  435.  
  436.     while(len-- > 0) {
  437.     (void) move(y,x);
  438.     *buf = inch() & 0x7f;
  439.     (void) addstr(buf);
  440.     x++;
  441.     }
  442. }
  443.  
  444. main (argc, argv)
  445. char  **argv; {
  446.     int     inloop = 1;
  447.     register int   c;
  448.     int     edistate = -1;
  449.     int     arg = 1;
  450.     int     narg;
  451.     int     nedistate;
  452.     int        running;
  453.     char    *revi;
  454.     char    *pname;
  455.  
  456.     pname = argv[0];
  457.     while (argc > 1 && argv[1][0] == '-') {
  458.     argv++;
  459.     argc--;
  460.         switch (argv[0][1]) {
  461.         case 'x':
  462.             Crypt = 1;
  463.             break;
  464.         case 'n':
  465.             numeric = 1;
  466.             break;
  467.         default:
  468.             (void) fprintf(stderr,"%s: unrecognized flag: %c\n",
  469.             pname,argv[0][1]);
  470.             exit(1);
  471.     }
  472.     }
  473.  
  474.     {
  475.     register    i;
  476.     for (i = 0; i < MAXCOLS; i++) {
  477.         fwidth[i] = DEFWIDTH;
  478.         precision[i] = DEFPREC;
  479.     }
  480.     }
  481.     curfile[0]=0;
  482.  
  483.     signals();
  484.     (void) initscr();
  485.     (void) clear();
  486.     nonl();
  487.     noecho ();
  488.     cbreak();
  489.     initkbd();
  490.     (void) strcpy(revmsg, pname);
  491.     for (revi=rev; *revi++ != ':';);
  492.     (void) strcat(revmsg, revi);
  493.     revi = revmsg+strlen(revmsg);
  494.     *--revi = 0;
  495.     (void) strcat(revmsg,"Type '?' for help.");
  496.     if (argc > 1) {
  497.     (void) strcpy(curfile,argv[1]);
  498.     readfile (argv[1], 0);
  499.     }
  500.     modflg = 0;
  501. #ifdef VENIX
  502.     setbuf (stdin, NULL);
  503. #endif
  504.     FullUpdate++;
  505.     while (inloop) { running = 1;
  506.     while (running) {
  507.     nedistate = -1;
  508.     narg = 1;
  509.     if (edistate < 0 && linelim < 0 && (changed || FullUpdate))
  510.         EvalAll (), changed = 0;
  511.     update();
  512. #ifndef SYSV3
  513.     (void) refresh(); /* 5.3 does a refresh in getch */ 
  514. #endif
  515.     c = nmgetch();
  516.     (void) move (1, 0);
  517.     (void) clrtoeol ();
  518.     (void) fflush (stdout);
  519.     seenerr = 0;
  520.     if ((c < ' ') || ( c == 0177 ))
  521.         switch (c) {
  522. #if defined(BSD42) || defined (BSD43)
  523.         case ctl (z):
  524.             deraw();
  525. #ifndef V7
  526.             (void) kill(getpid(),SIGTSTP);
  527. #endif
  528.  
  529.             /* the pc stops here */
  530.  
  531.             goraw();
  532.             break;
  533. #endif
  534.         case ctl (r):
  535.         case ctl (l):
  536.             FullUpdate++;
  537.             (void) clearok(stdscr,1);
  538.             break;
  539.         default:
  540.             error ("No such command  (^%c)", c + 0100);
  541.             break;
  542.         case ctl (b):
  543.             while (--arg>=0) {
  544.             if (curcol)
  545.                 curcol--;
  546.             else
  547.                 error ("At column A");
  548.             while(col_hidden[curcol] && curcol)
  549.                 curcol--;
  550.             }
  551.             break;
  552.         case ctl (c):
  553.             running = 0;
  554.             break;
  555.         case ctl (e):
  556.             switch (nmgetch()) {
  557.             case 'j':
  558.             case ctl(n):
  559.             doend(1,0);
  560.             break;
  561.             case 'k':
  562.             case ctl(p):
  563.             doend(-1,0);
  564.             break;
  565.             case 'h':
  566.             case ctl(b):
  567.             doend(0,-1);
  568.             break;
  569.             case 'l':
  570.             case ctl(f):
  571.             doend(0,1);
  572.             break;
  573.             default:
  574.             error("Invalid end command");
  575.             break;
  576.             }
  577.             break;
  578.         case ctl (f):
  579.             while (--arg>=0) {
  580.             if (curcol < MAXCOLS - 1)
  581.                 curcol++;
  582.             else
  583.                 error ("The table can't be any wider");
  584.             while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  585.                 curcol++;
  586.             }
  587.             break;
  588.         case ctl (g):
  589.         case ctl ([):
  590.             showrange = 0;
  591.             linelim = -1;
  592.             (void) move (1, 0);
  593.             (void) clrtoeol ();
  594.             break;
  595.         case 0177:
  596.         case ctl (h):
  597.             while (--arg>=0) if (linelim > 0)
  598.             line[--linelim] = 0;
  599.             break;
  600.         case ctl (i):         /* tab */
  601.             if (linelim > 0) {
  602.             if (!showrange) {
  603.                 startshow();
  604.             } else {
  605.                 showdr();
  606.                 linelim = strlen(line);
  607.                 line[linelim++] = ' ';
  608.                 line[linelim] = 0;
  609.                 showrange = 0;
  610.             }
  611.             linelim = strlen (line);
  612.             }
  613.             break;
  614.         case ctl (m):
  615.         case ctl (j):
  616.             showrange = 0;
  617.             if (linelim < 0)
  618.             line[linelim = 0] = 0;
  619.             else {
  620.             linelim = 0;
  621.             (void) yyparse ();
  622.             linelim = -1;
  623.             }
  624.             break;
  625.         case ctl (n):
  626.             while (--arg>=0) {
  627.             if (currow < MAXROWS - 1)
  628.                 currow++;
  629.             else
  630.                 error ("The table can't be any longer");
  631.             while (row_hidden[currow] && (currow < MAXROWS - 1))
  632.                 currow++;
  633.             }
  634.             break;
  635.         case ctl (p):
  636.             while (--arg>=0) {
  637.             if (currow)
  638.                 currow--;
  639.             else
  640.                 error ("At row zero");
  641.             while (row_hidden[currow] && currow)
  642.                 currow--;
  643.             }
  644.             break;
  645.         case ctl (q):
  646.             break;    /* ignore flow control */
  647.         case ctl (s):
  648.             break;    /* ignore flow control */
  649.         case ctl (t):
  650.             error("Toggle - n:numeric  t:top row  x:encryption");
  651.             (void) refresh();
  652.             switch (nmgetch()) {
  653.             case 't': case 'T':
  654.                 showme ^= 1;
  655.                 repaint(lastmx, lastmy, fwidth[lastcol]);
  656.                 break;
  657.             case 'n': case 'N':
  658.                 numeric ^= 1;
  659.                 error("Numeric input %sabled.",numeric? "en":"dis");
  660.                 break;
  661.             case 'x': case 'X':
  662.                 Crypt ^= 1;
  663.                 error("Encryption %sabled.",Crypt? "en":"dis");
  664.                 break;
  665.             default:
  666.                 error("Bad toggle switch");
  667.             }
  668.             break;
  669.         case ctl (u):
  670.             narg = arg * 4;
  671.             nedistate = 1;
  672.             break;
  673.         case ctl (v):    /* insert variable name */
  674.             if (linelim > 0) {
  675.             (void) sprintf (line+linelim,"%s", v_name(currow, curcol));
  676.             linelim = strlen (line);
  677.             }
  678.             break;
  679.         case ctl (w):    /* insert variable expression */
  680.             if (linelim > 0) editexp(currow,curcol);
  681.             break;
  682.         case ctl (a):    /* insert variable value */
  683.             if (linelim > 0) {
  684.             struct ent *p = tbl[currow][curcol];
  685.  
  686.             if (p && p -> flags & is_valid) {
  687.                 (void) sprintf (line + linelim, "%.*f",
  688.                     precision[curcol],p -> v);
  689.                 linelim = strlen (line);
  690.             }
  691.             }
  692.             break;
  693.         }
  694.     else
  695.         if ('0' <= c && c <= '9' && ( (numeric && edistate >= 0) ||
  696.             (!numeric && (linelim < 0 || edistate >= 0))))
  697.         {
  698.         if (edistate != 0) {
  699.             if (c == '0')      /* just a '0' goes to left col */
  700.             curcol = 0;
  701.             else {
  702.                 nedistate = 0;
  703.                 narg = c - '0';
  704.             }
  705.         } else {
  706.             nedistate = 0;
  707.             narg = arg * 10 + (c - '0');
  708.         }
  709.         }
  710.         else
  711.         if (linelim >= 0) {     /* Editing line */
  712.             switch(c) {
  713.             case ')':
  714.                 if (showrange) {
  715.                 showdr();
  716.                     showrange = 0;
  717.                     linelim = strlen (line);
  718.                 }
  719.                 break;
  720.                default:
  721.                 break;
  722.             }
  723.             line[linelim++] = c;
  724.             line[linelim] = 0;
  725.         }
  726.         else
  727.             switch (c) {
  728.             case ':':
  729.                 break;    /* Be nice to vi users */
  730.  
  731.             case '0': case '1': case '2': case '3': case '4':
  732.             case '5': case '6': case '7': case '8': case '9':
  733.             case '-': case '.': case '+':
  734.                 (void) sprintf(line,"let %s = %c",
  735.                     v_name(currow, curcol), c);
  736.                 linelim = strlen (line);
  737.                 break;
  738.  
  739.             case '=':
  740.                 (void) sprintf(line,"let %s = ",
  741.                         v_name(currow, curcol));
  742.                 linelim = strlen (line);
  743.                 break;
  744.  
  745.             case '!':
  746.                 {
  747.                 /*
  748.                  *  "! command"  executes command
  749.                  *  "!"    forks a shell
  750.                  *  "!!" repeats last command
  751.                  */
  752.                 char *shl;
  753.                 int pid, temp;
  754.                 char cmd[MAXCMD];
  755.                 static char lastcmd[MAXCMD];
  756.  
  757.                 if (!(shl = getenv("SHELL")))
  758.                 shl = "/bin/sh";
  759.  
  760.                 deraw();
  761.                 (void) fputs("! ", stdout);
  762.                 (void) fflush(stdout);
  763.                 (void) fgets(cmd, MAXCMD, stdin);
  764.                 cmd[strlen(cmd) - 1] = '\0';    /* clobber \n */
  765.                 if(strcmp(cmd,"!") == 0)        /* repeat? */
  766.                     (void) strcpy(cmd, lastcmd);
  767.                 else
  768.                     (void) strcpy(lastcmd, cmd);
  769.  
  770.                 if (!(pid = fork()))
  771.                 {
  772.                     if(strlen(cmd))
  773.                     (void)execl(shl,shl,"-c",cmd,(char *)0);
  774.                 else
  775.                     (void) execl(shl, shl, (char *)0);
  776.                 exit(-127);
  777.                 }
  778.  
  779.                 while (pid != wait(&temp));
  780.  
  781.                 (void) printf("Press <return> to continue\n");
  782.                 (void)nmgetch();
  783.                 goraw();
  784.                 break;
  785.                 }
  786.  
  787.             case '/':
  788.                 error("c:copy x:erase v:value f:fill d:define u:undefine s:show");
  789.                 (void) refresh();
  790.                 switch (nmgetch()) {
  791.                 case 'c':
  792.                 (void) sprintf(line,"copy [dest_range src_range] ");
  793.                 linelim = strlen(line);
  794.                 startshow();
  795.                 break;
  796.                 case 'x':
  797.                 (void) sprintf(line,"erase [range] ");
  798.                 linelim = strlen(line);
  799.                 startshow();
  800.                 break;
  801.                 case 'v':
  802.                 (void) sprintf(line, "value [range] ");
  803.                 linelim = strlen(line);
  804.                 startshow();
  805.                 break;
  806.                 case 'f':
  807.                 (void) sprintf(line,"fill [range start inc] ");
  808.                 linelim = strlen(line);
  809.                 startshow();
  810.                 break;
  811.                 case 'd':
  812.                 (void) sprintf(line,"define [string range] \"");
  813.                 linelim = strlen(line);
  814.                 startshow();
  815.                 modflg++;
  816.                 break;
  817.                 case 'u':
  818.                 (void) sprintf(line,"undefine [range] ");
  819.                 linelim = strlen(line);
  820.                 modflg++;
  821.                 break;
  822.                 case 's':
  823.                 {
  824.                 FILE *f;
  825.                 int pid;
  826.                 f = openout("| sort | less", &pid);
  827.                 if (!f) {
  828.                     error("Cant open pipe to sort");
  829.                     break;
  830.                 }
  831.                 list_range(f);
  832.                 closeout(f, pid);
  833.                 break;
  834.                 }
  835.                default:
  836.                 error("Invalid region operation");
  837.                 }
  838.                 break;
  839.             case '$':
  840.                 {
  841.                 register struct ent *p;
  842.  
  843.                 curcol = MAXCOLS - 1;
  844.                 while (!VALID_CELL(p, currow, curcol) && curcol > 0)
  845.                 curcol--;
  846.                 break;
  847.                 }
  848.             case '#':
  849.                 {
  850.                 register struct ent *p;
  851.  
  852.                 currow = MAXROWS - 1;
  853.                 while (!VALID_CELL(p, currow, curcol) && currow > 0)
  854.                 currow--;
  855.                 break;
  856.                 }
  857.             case 'w':
  858.                 {
  859.                 register struct ent *p;
  860.  
  861.                 while (--arg>=0) {
  862.                 do {
  863.                     if (curcol < MAXCOLS - 1)
  864.                     curcol++;
  865.                     else {
  866.                     if (currow < MAXROWS - 1) {
  867.                         while(++currow < MAXROWS - 1 &&
  868.                                 row_hidden[currow]) /* */;
  869.                         curcol = 0;
  870.                     } else {
  871.                         error("End of the table");
  872.                         break;
  873.                     }
  874.                     }
  875.                 } while(col_hidden[curcol] ||
  876.                     !VALID_CELL(p, currow, curcol));
  877.                 }
  878.                 break;
  879.                 }
  880.             case 'b':
  881.                 {
  882.                 register struct ent *p;
  883.  
  884.                 while (--arg>=0) {
  885.                 do {
  886.                     if (curcol) 
  887.                     curcol--;
  888.                     else {
  889.                     if (currow) {
  890.                         while(--currow &&
  891.                         row_hidden[currow]) /* */;
  892.                         curcol = MAXCOLS - 1;
  893.                     } else {
  894.                         error ("At start of table");
  895.                         break;
  896.                     }
  897.                     }
  898.                 } while(col_hidden[curcol] ||
  899.                     !VALID_CELL(p, currow, curcol));
  900.                 }
  901.                 break;
  902.                 }
  903.             case '^':
  904.                 currow = 0;
  905.                 break;
  906.             case '?':
  907.                 help ();
  908.                 break;
  909.             case '"':
  910.                 (void) sprintf (line, "label %s = \"",
  911.                         v_name(currow, curcol));
  912.                 linelim = strlen (line);
  913.                 break;
  914.             case '<':
  915.                 (void) sprintf (line, "leftstring %s = \"",
  916.                     v_name(currow, curcol));
  917.                 linelim = strlen (line);
  918.                 break;
  919.             case '>':
  920.                 (void) sprintf (line, "rightstring %s = \"",
  921.                    v_name(currow, curcol));
  922.                 linelim = strlen (line);
  923.                 break;
  924.             case 'e':
  925.                 editv (currow, curcol);
  926.                 break;
  927.             case 'E':
  928.                 edits (currow, curcol);
  929.                 break;
  930.             case 'f':
  931.                 if (arg == 1)
  932.                     (void) sprintf (line, "format [for column] %s ",
  933.                     coltoa(curcol));
  934.                 else {
  935.                 (void) sprintf(line, "format [for columns] %s:",
  936.                     coltoa(curcol));
  937.                 (void) sprintf(line+strlen(line), "%s ",
  938.                     coltoa(curcol+arg-1));
  939.                 }
  940.                 error("Current format is %d %d",
  941.                     fwidth[curcol],precision[curcol]);
  942.                 linelim = strlen (line);
  943.                 break;
  944.             case 'g':
  945.                 (void) sprintf (line, "goto [v] ");
  946.                 linelim = strlen (line);
  947.                 break;
  948.             case 'P':
  949.                 (void) sprintf (line, "put [\"dest\" range] \"");
  950.                 if (*curfile)
  951.                     error("Default path is '%s'",curfile);
  952.                 linelim = strlen (line);
  953.                 break;
  954.             case 'M':
  955.                 (void) sprintf (line, "merge [\"source\"] \"");
  956.                 linelim = strlen (line);
  957.                 break;
  958.             case 'R':
  959.                 (void) sprintf (line,"merge [\"macro_file\"] \"%s/", mdir);
  960.                 linelim = strlen (line);
  961.                 break;
  962.             case 'D':
  963.                 (void) sprintf (line, "mdir [\"macro_directory\"] \"");
  964.                 linelim = strlen (line);
  965.                 break;
  966.             case 'G':
  967.                 (void) sprintf (line, "get [\"source\"] \"");
  968.                 if (*curfile)
  969.                     error("Default file is '%s'",curfile);
  970.                 linelim = strlen (line);
  971.                 break;
  972.             case 'W':
  973.                 (void) sprintf (line, "write [\"dest\" range] \"");
  974.                 linelim = strlen (line);
  975.                 break;
  976.             case 'T':    /* tbl output */
  977.                 (void) sprintf (line, "tbl [\"dest\" range] \"");
  978.                 linelim = strlen (line);
  979.                 break;
  980.             case 'i':
  981.                 switch (get_qual()) {
  982.                 case 'r':
  983.                 insertrow(arg);
  984.                 break;
  985.                 case 'c':
  986.                 insertcol(arg);
  987.                 break;
  988.                 default:
  989.                 error("Invalid insert command");
  990.                 break;
  991.                 }
  992.                 break;
  993.             case 'd':
  994.                 switch (get_qual()) {
  995.                 case 'r':
  996.                 deleterow(arg);
  997.                 break;
  998.                 case 'c':
  999.                 deletecol(arg);
  1000.                 break;
  1001.                 default:
  1002.                 error("Invalid delete command");
  1003.                 break;
  1004.                 }
  1005.                 break;
  1006.             case 'v':
  1007.                 switch (get_qual()) {
  1008.                 case 'r':
  1009.                 rowvalueize(arg);
  1010.                 modflg++;
  1011.                 break;
  1012.                 case 'c':
  1013.                 colvalueize(arg);
  1014.                 modflg++;
  1015.                 break;
  1016.                 default:
  1017.                 error("Invalid value command");
  1018.                 break;
  1019.                 }
  1020.                 break;
  1021.             case 'p':
  1022.                 {
  1023.                 register qual;
  1024.                 qual = get_qual();
  1025.                 while (arg--)
  1026.                     pullcells(qual);
  1027.                 break;
  1028.                 }
  1029.             case 'x':
  1030.                 {
  1031.                 register struct ent **p;
  1032.                 register int c1;
  1033.  
  1034.                 flush_saved();
  1035.                 for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
  1036.                 p = &tbl[currow][c1];
  1037.                 if (*p) {
  1038.                         free_ent(*p);
  1039.                         *p = 0;
  1040.                 }
  1041.                 }
  1042.                 sync_refs();
  1043.                 FullUpdate++;
  1044.                 }
  1045.                 break;
  1046.             case 'Q':
  1047.             case 'q':
  1048.                 running = 0;
  1049.                 break;
  1050.             case 'h':
  1051.                 while (--arg>=0) {
  1052.                 if (curcol)
  1053.                     curcol--;
  1054.                 else
  1055.                     error ("At column A");
  1056.                 while(col_hidden[curcol] && curcol)
  1057.                     curcol--;
  1058.                 }
  1059.                 break;
  1060.             case 'j':
  1061.                 while (--arg>=0) {
  1062.                 if (currow < MAXROWS - 1)
  1063.                     currow++;
  1064.                 else
  1065.                     error ("The table can't be any longer");
  1066.                 while (row_hidden[currow]&&(currow<MAXROWS-1))
  1067.                     currow++;
  1068.                 }
  1069.                 break;
  1070.             case 'k':
  1071.                 while (--arg>=0) {
  1072.                 if (currow)
  1073.                     currow--;
  1074.                 else
  1075.                     error ("At row zero");
  1076.                 while (row_hidden[currow] && currow)
  1077.                     currow--;
  1078.                 }
  1079.                 break;
  1080.             case ' ':
  1081.             case 'l':
  1082.                 while (--arg>=0) {
  1083.                 if (curcol < MAXCOLS - 1)
  1084.                     curcol++;
  1085.                 else
  1086.                     error ("The table can't be any wider");
  1087.                 while(col_hidden[curcol]&&(curcol<MAXCOLS-1))
  1088.                     curcol++;
  1089.                 }
  1090.                 break;
  1091.             case 'm':
  1092.                 savedrow = currow;
  1093.                 savedcol = curcol;
  1094.                 break;
  1095.             case 'c': {
  1096.                 register struct ent *p = tbl[savedrow][savedcol];
  1097.                 register c1;
  1098.                 register struct ent *n;
  1099.                 if (!p)
  1100.                 break;
  1101.                 FullUpdate++;
  1102.                 modflg++;
  1103.                 for (c1 = curcol; arg-- && c1 < MAXCOLS; c1++) {
  1104.                 n = lookat (currow, c1);
  1105.                 (void) clearent(n);
  1106.                 n -> flags = p -> flags;
  1107.                 n -> v = p -> v;
  1108.                 n -> expr = copye(p->expr,
  1109.                         currow - savedrow,
  1110.                         c1 - savedcol);
  1111.                 n -> label = 0;
  1112.                 if (p -> label) {
  1113.                     n -> label = (char *)
  1114.                          xmalloc((unsigned)strlen(p->label)+1);
  1115.                 (void) strcpy (n -> label, p -> label);
  1116.                 }
  1117.                 }
  1118.                 break;
  1119.             }
  1120.             case 'z':
  1121.                 switch (get_qual()) {
  1122.                 case 'r':
  1123.                 hiderow(arg);
  1124.                 break;
  1125.                 case 'c':
  1126.                 hidecol(arg);
  1127.                 break;
  1128.                 default:
  1129.                 error("Invalid zap command");
  1130.                 break;
  1131.                 }
  1132.                 break;
  1133.             case 's':
  1134.                 switch (get_qual()) {
  1135.                 case 'r':
  1136.                 rowshow_op();
  1137.                 break;
  1138.                 case 'c':
  1139.                 colshow_op();
  1140.                 break;
  1141.                 default:
  1142.                 error("Invalid show command");
  1143.                 break;
  1144.                 }
  1145.                 break;
  1146.             case 'a':
  1147.                 switch (get_qual()) {
  1148.                 case 'r':
  1149.                 while (arg--)
  1150.                     duprow();
  1151.                 break;
  1152.                 case 'c':
  1153.                 while (arg--)
  1154.                     dupcol();
  1155.                 break;
  1156.                 default:
  1157.                 error("Invalid add row/col command");
  1158.                 break;
  1159.                 }
  1160.                 break;
  1161.             default:
  1162.                 if ((c & 0177) != c)
  1163.                 error("Weird character, decimal '%d'.\n",
  1164.                     (int) c);
  1165.                 else
  1166.                     error ("No such command  (%c)", c);
  1167.                 break;
  1168.             }
  1169.     edistate = nedistate;
  1170.     arg = narg;
  1171.     }                /* while (running) */
  1172.     inloop = modcheck(" before exiting");
  1173.     }                /*  while (inloop) */
  1174.     deraw();
  1175.     endwin();
  1176.     exit(0);
  1177.     /*NOTREACHED*/
  1178. }
  1179.  
  1180. startshow()
  1181. {
  1182.     showrange = 1;
  1183.     showsr = currow;
  1184.     showsc = curcol;
  1185. }
  1186.  
  1187. showdr()
  1188. {
  1189.     int     minsr, minsc, maxsr, maxsc;
  1190.  
  1191.     minsr = showsr < currow ? showsr : currow;
  1192.     minsc = showsc < curcol ? showsc : curcol;
  1193.     maxsr = showsr > currow ? showsr : currow;
  1194.     maxsc = showsc > curcol ? showsc : curcol;
  1195.     (void) sprintf (line+linelim,"%s", r_name(minsr, minsc, maxsr, maxsc));
  1196. }
  1197.  
  1198.  
  1199. goraw()
  1200. {
  1201. #if SYSV2 || SYSV3
  1202.     fixterm();
  1203. #else
  1204.     cbreak();
  1205.     nonl();
  1206.     noecho ();
  1207. #endif
  1208.     kbd_again();
  1209.     (void) clear();
  1210.     FullUpdate++;
  1211. }
  1212.  
  1213. deraw()
  1214. {
  1215.     (void) move (LINES - 1, 0);
  1216.     (void) clrtoeol();
  1217.     (void) refresh();
  1218. #if SYSV2 || SYSV3
  1219.     resetterm();
  1220. #else
  1221.     nocbreak();
  1222.     nl();
  1223.     echo();
  1224. #endif
  1225.     resetkbd();
  1226. }
  1227.  
  1228. signals()
  1229. {
  1230. #ifdef SYSV3
  1231.     void quit();
  1232.     void timeout();
  1233. #else
  1234.     int quit();
  1235.     int timeout();
  1236. #endif
  1237.  
  1238.     (void) signal(SIGINT, SIG_IGN);
  1239.     (void) signal(SIGQUIT, quit);
  1240.     (void) signal(SIGPIPE, quit);
  1241.     (void) signal(SIGTERM, quit);
  1242.     (void) signal(SIGALRM, timeout);
  1243.     (void) signal(SIGFPE, quit);
  1244.     (void) signal(SIGBUS, quit);
  1245. }
  1246.  
  1247. #ifdef SYSV3
  1248. void
  1249. #endif
  1250. quit()
  1251. {
  1252.     deraw();
  1253.     resetkbd();
  1254.     endwin();
  1255.     exit(1);
  1256. }
  1257.  
  1258. modcheck(endstr)
  1259. char *endstr;
  1260. {
  1261.     if (modflg && curfile[0]) {
  1262.     char ch, lin[100];
  1263.  
  1264.     (void) move (0, 0);
  1265.     (void) clrtoeol ();
  1266.     (void) sprintf (lin,"File '%s' is modified, save%s? ",curfile,endstr);
  1267.     (void) addstr (lin);
  1268.     (void) refresh();
  1269.     ch = nmgetch();
  1270.      if (ch != 'n' && ch != 'N')
  1271.          if (writefile(curfile, 0, 0, maxrow, maxcol) < 0)
  1272.          return (1);
  1273.     else if (ch == ctl (g) || ch == ctl([)) return(1);
  1274.     } else if (modflg) {
  1275.     char ch, lin[100];
  1276.  
  1277.     (void) move (0, 0);
  1278.     (void) clrtoeol ();
  1279.     (void) sprintf (lin,"Do you want a chance to save the data? ");
  1280.     (void) addstr (lin);
  1281.     (void) refresh();
  1282.     ch = nmgetch();
  1283.     if (ch == 'n' || ch == 'N') return(0);
  1284.     else return(1);
  1285.       }
  1286.     return(0);
  1287. }
  1288.  
  1289.     
  1290. writefile (fname, r0, c0, rn, cn)
  1291. char *fname;
  1292. {
  1293.     register FILE *f;
  1294.     register struct ent **p;
  1295.     register r, c;
  1296.     char save[1024];
  1297.     int pid;
  1298.  
  1299.     if (Crypt) {
  1300.     return (cwritefile(fname, r0, c0, rn, cn));
  1301.     }
  1302.  
  1303.     if (*fname == 0) fname = &curfile[0];
  1304.  
  1305.     (void) strcpy(save,fname);
  1306.  
  1307.     f = openout(fname, &pid);
  1308.     if (f == 0) {
  1309.     error ("Can't create %s", fname);
  1310.     return (-1);
  1311.     }
  1312.  
  1313.     (void) fprintf (f, "# This data file was generated by the Spreadsheet ");
  1314.     (void) fprintf (f, "Calculator.\n");
  1315.     (void) fprintf (f, "# You almost certainly shouldn't edit it.\n\n");
  1316.     for (c=0; c<MAXCOLS; c++)
  1317.     if (fwidth[c] != DEFWIDTH || precision[c] != DEFPREC)
  1318.         (void) fprintf (f, "format %s %d %d\n",coltoa(c),fwidth[c],precision[c]);
  1319.     write_range(f);
  1320.     if (mdir) 
  1321.         (void) fprintf(f, "mdir \"%s\"\n", mdir);
  1322.     for (r=r0; r<=rn; r++) {
  1323.     p = &tbl[r][0];
  1324.     for (c=c0; c<=cn; c++, p++)
  1325.         if (*p) {
  1326.         if ((*p)->label) {
  1327.             edits(r,c);
  1328.             (void) fprintf(f, "%s\n",line);
  1329.         }
  1330.         if ((*p)->flags&is_valid) {
  1331.             editv (r, c);
  1332.             (void) fprintf (f, "%s\n",line);
  1333.         }
  1334.         }
  1335.     }
  1336.  
  1337.     closeout(f, pid);
  1338.  
  1339.     if (!pid) {
  1340.         (void) strcpy(curfile, save);
  1341.         modflg = 0;
  1342.         error("File '%s' written.",curfile);
  1343.     }
  1344.  
  1345.     return (0);
  1346. }
  1347.  
  1348. readfile (fname,eraseflg)
  1349. char *fname;
  1350. int eraseflg;
  1351. {
  1352.     register FILE *f;
  1353.     char save[1024];
  1354.  
  1355.     if (*fname == '*' && mdir) { 
  1356.        (void) strcpy(save, mdir);
  1357.        *fname = '/';
  1358.        (void) strcat(save, fname);
  1359.     } else {
  1360.         if (*fname == 0)
  1361.         fname = &curfile[0];
  1362.         (void) strcpy(save,fname);
  1363.     }
  1364.  
  1365.     if (Crypt)  {
  1366.     creadfile(save, eraseflg);
  1367.     return;
  1368.     }
  1369.  
  1370.     if (eraseflg && strcmp(fname,curfile) && modcheck(" first")) return;
  1371.  
  1372.     f = fopen (save, "r");
  1373.     if (f==0) {
  1374.     error ("Can't read %s", save);
  1375.     return;
  1376.     }
  1377.  
  1378.     if (eraseflg) erasedb ();
  1379.  
  1380.     while (fgets(line,sizeof line,f)) {
  1381.     linelim = 0;
  1382.     if (line[0] != '#') (void) yyparse ();
  1383.     }
  1384.     (void) fclose (f);
  1385.     linelim = -1;
  1386.     modflg++;
  1387.     if (eraseflg) {
  1388.     (void) strcpy(curfile,save);
  1389.     modflg = 0;
  1390.     }
  1391.     EvalAll();
  1392. }
  1393.  
  1394. erasedb () {
  1395.     register r, c;
  1396.     for (c = 0; c<=maxcol; c++) {
  1397.     fwidth[c] = DEFWIDTH;
  1398.     precision[c] = DEFPREC;
  1399.     }
  1400.  
  1401.     for (r = 0; r<=maxrow; r++) {
  1402.     register struct ent **p = &tbl[r][0];
  1403.     for (c=0; c++<=maxcol; p++)
  1404.         if (*p) {
  1405.         if ((*p)->expr) efree ((*p) -> expr);
  1406.         if ((*p)->label) xfree ((char *)((*p) -> label));
  1407.         xfree ((char *)(*p));
  1408.         *p = 0;
  1409.         }
  1410.     }
  1411.     maxrow = 0;
  1412.     maxcol = 0;
  1413.     clean_range();
  1414.     FullUpdate++;
  1415. }
  1416.  
  1417. #if DEBUG
  1418. debugout(g,fmt,args) FILE *g; char *fmt; {
  1419.     int op;
  1420.  
  1421.     if (g == 0) g = fopen("debug","a"),op = 1;
  1422.     if (g == 0) return;
  1423.  
  1424.     _doprnt(fmt, &args, g);
  1425.  
  1426.     (void) fflush(g);
  1427.     if (op) (void) fclose(g);
  1428. }
  1429. #endif
  1430.